﻿using System;
using System.Collections.Generic;
using System.IO;
using MathNet.Numerics.LinearAlgebra.Double;
using MathNet.Numerics.LinearAlgebra.Generic;
using innovations.ml.core.models;

namespace innovations.ml.data
{
    public class CSVLoader
    {
        public CSVLoader(string path)
        {
            Path = path;
        }

        public void Load(int numberOfRecords = -1)
        {
            if (string.IsNullOrEmpty(Path))
                throw new ArgumentNullException("Path property must not be null.");
            string[] lines = File.ReadAllLines(Path);
            int columnCount = lines[0].Split(',').Length;

            if (numberOfRecords == -1)
                numberOfRecords = lines.Length;

            ColumnsArray = new List<double[]>();
            // Create an array in #columnsArray for each column
            for (int i = 0; i < columnCount; i++)
                ColumnsArray.Add(new double[lines.Length]);

            // fill arrays in #columnsArray with data
            for (int i = 0; i < numberOfRecords; i++)
            {
                for (int j = 0; j < columnCount; j++)
                {
                    string[] line = lines[i].Split(',');
                    ColumnsArray[j][i] = Convert.ToDouble(line[j]);
                }
            }
            this.X = LoadX();
            this.Y = LoadY();
        }

        public Matrix<double> LoadX()
        {
            if (ColumnsArray == null || ColumnsArray.Count == 0)
                throw new ArgumentNullException("X data hasn't been loaded.");
            int rowCount = ColumnsArray[0].Length;
            List<Vector<double>> xColumnVectors = new List<Vector<double>>();
            for (int i = 0; i < ColumnsArray.Count; i++)
            {
                if (i < ColumnsArray.Count - 1)
                    xColumnVectors.Add(new DenseVector(ColumnsArray[i]));
            }
            return DenseMatrix.CreateFromColumns(xColumnVectors);
        }

        public Vector<double> LoadY()
        {
            if (ColumnsArray == null || ColumnsArray.Count == 0)
                throw new ArgumentNullException("Y data hasn't been loaded.");
            return new DenseVector(ColumnsArray[ColumnsArray.Count - 1]);
        }

        public string Path { get; set; }
        public Matrix<double> X { get; set; }
        public Vector<double> Y { get; set; }
        private List<double[]> ColumnsArray;
    }
}
